﻿using System;
using System.Diagnostics;
using SfsTools.Core;
using mindvnas.Common;

namespace SfsTools.List
{
    /// <summary>
    /// Implements the <em>format</em> application.
    /// </summary>
    public class Program : ConsoleBase
    {
        #region Properties

        /// <summary>
        /// Contains the path to the image file to open.
        /// </summary>
        private String FImageFile;
        /// <summary>
        /// Contains the virtual path to list.
        /// </summary>
        private String FVirtualPath;
        /// <summary>
        /// Controls whether to list subdirectories as well.
        /// </summary>
        private bool FRecurse;

        #endregion

        #region Methods

        #region Entry point
        /// <summary>
        /// Entry point.
        /// </summary>
        /// <param name="arguments"></param>
        [DebuggerStepThrough]
        static void Main(String[] arguments)
        {
            new Program().Process(arguments);
        }
        #endregion

        #region Arguments

        /// <summary>
        /// Invoked before processing arguments.
        /// </summary>
        protected override void OnBeforeProcessArguments()
        {
            FVirtualPath = new String(System.IO.Path.PathSeparator, 1);
        }

        /// <summary>
        /// Invoked after processing arguments.
        /// </summary>
        protected override void OnAfterProcessArguments()
        {
            if (FVirtualPath != null)
            {
                // If not an absolute path, assume it is an absolue path.
                if (!FVirtualPath.StartsWith(new String(System.IO.Path.DirectorySeparatorChar, 1)))
                    FVirtualPath = String.Concat(System.IO.Path.DirectorySeparatorChar, FVirtualPath);
            }
        }

        /// <summary>
        /// Processes the specified command-line argument.
        /// </summary>
        /// <param name="argument">The command-line argument.</param>
        protected override void ProcessArgument(ConsoleBaseArgument argument)
        {
            if (argument.Name == "-image")
            {
                FImageFile = argument.Value;
                Arguments.Add(argument);
            }
            else if (argument.Name == "-path")
            {
                FVirtualPath = argument.Value;
            }
            else if (argument.Name == "-r")
            {
                FRecurse = true;
            }
            else
            {
                base.ProcessArgument(argument);
            }
        }

        /// <summary>
        /// Displays an usage notice.
        /// </summary>
        [DebuggerStepThrough]
        protected override void UsageParameters()
        {
            base.UsageParameters();
            //
            UsageParameter("-image", "Location of image file to create");
            UsageParameter("-path", "Virtual path to list");
            UsageParameter("-r", "Enables recursive listing");
        }

        #endregion

        /// <summary>
        /// Performs whatever the application does.
        /// </summary>
        protected override void ProcessCore()
        {
#if DEBUG
            String pathToVolume = @"E:\Work\VisualStudio\SfsTools\Core\";
            FImageFile = pathToVolume + "disk";
            //FImageFile = @"d:\Downloads\.sfs\floppy.img";
#endif
            if (HelpRequested || FImageFile == null || FVirtualPath == null)
            {
                HelpRequested = true;
                base.ProcessCore();
            }
            else
            {
                using (FileBackedVolume volume = FileBackedVolume.Open(FImageFile))
                {
                    using (TransactionalVolume trv = new TransactionalVolume(volume))
                    {
                        using (FileSystem fs = new FileSystem(trv))
                        {
                            FRecurse = true;
                            // Get root directory.
                            IDirectory root = fs.RootDirectory;
                            List(root);
                            String name = "a"; // String.Format("teszt_{0}", Guid.NewGuid().ToString());
                            IDirectory dir = root.CreateDirectory(name);
                            String longName = name;// new String('a', 255 * 64 + 54 - 4);
                            IDirectory dir2 = dir.CreateDirectory(longName);
                            WriteLine(dir2.GetFullPath());
                            //trv.Commit();
                            trv.Discard();
                        }
                    }
                }
                Console.ReadLine();
            }
        }

        /// <summary>
        /// Lists the contents of the specified directory.
        /// </summary>
        /// <param name="directory"></param>
        [DebuggerStepThrough]
        private void List(IDirectory directory)
        {
            List(directory, FRecurse);
            WriteLine();
        }

        /// <summary>
        /// Lists the contents of the specified directory.
        /// </summary>
        /// <param name="directory"></param>
        /// <param name="recurse"></param>
        private void List(IDirectory directory, bool recurse)
        {
            WriteLine("List of {0}", directory.GetFullPath());
            // list files
            foreach (IDirectory dir in directory.GetDirectories())
            {
                WriteLine("  {0} {1}", dir.Name, dir.LastUpdate);
            }
            if (recurse)
            {
                foreach (IDirectory dir in directory.GetDirectories())
                {
                    List(dir, recurse);
                }
            }
        }

        [DebuggerStepThrough]
        private static String Display(long value)
        {
            if (value < 1024)
                return String.Format("{0} B", value);
            if (value < 1024 * 1024)
                return String.Format("{0} KiB", value / 1024);
            if (value < 1024 * 1024 * 1024)
                return String.Format("{0} MiB", (value / (1024 * 1024.0)).ToString("0.00"));
            return String.Format("{0} GiB", (value / (1024 * 1024 * 1024.0)).ToString("0.00"));
        }

        #endregion

        #region Constructors
        /// <overloads>Initializes a new instance of <see cref="Program"/>.</overloads>
        /// <summary>
        /// Initializes a new instance of <see cref="Program"/>.
        /// </summary>
        [DebuggerStepThrough]
        public Program()
            : base()
        {
        }
        #endregion
    }
}
